//If there is insufficient memory, change jam space size in - C:\Java_ME_platform_SDK_3.0\runtimes\cldc-hi-javafx\bin\jwc_properties.ini

import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.game.GameCanvas;
import java.io.IOException;
import javax.microedition.lcdui.game.LayerManager;
import javax.microedition.lcdui.game.Sprite;
import javax.microedition.lcdui.game.TiledLayer;
import java.util.Timer;

public class FighterCanvas extends GameCanvas implements Runnable{

    public FighterCanvas() {
	  super(true);

          try {

	    //create and load the plane image and then center it on screen
	    planeImg = Image.createImage("/plane.png");
	    planeX = CENTER_X;
            planeY = CENTER_Y;
            planeSprite =new Sprite(planeImg, 29, 14);
            planeSprite.defineReferencePixel(planeSprite.getWidth(), planeSprite.getHeight()/2);
            planeSprite.setPosition(planeX, planeY);

            expImage = Image.createImage("/exp.png");
            planeExpSprite = new Sprite(expImage, 25, 25);

            // create the tiledlayer background
            backgroundImg = Image.createImage("/background.png");
            background = new TiledLayer(1000, 1, backgroundImg, 1, 160);

            titleImg = Image.createImage("/titleScreen.png");
        
            mLayerManager = new LayerManager();
            mLayerManager.append(planeSprite);
            mLayerManager.append(createBackground());

            fighterBulletSprite = new FighterBulletSprite(this);
            fighterBulletSprite.start();

            enemyImage1 = Image.createImage("/enemy1.png");
            for(int i=0; i<3; i++){
                for(int t=0; t<5; t++){
                    enemySprite[i][t] = new EnemySprite(enemyImage1, 29, 14);
                }
            }

	  } catch(IOException ioex) { System.err.println(ioex); }
	}

	public void start() {

	  Thread runner = new Thread(this);
	  runner.start();
	}

        public void stop() {
            stop = true;
            return;
        }
        
        Sprite getPlaneSprite(){
               return this.planeSprite;
        }

    private TiledLayer createBackground() throws IOException {
        // set the background
        for (int i = 0; i < 160; i++) {
            background.setCell(i, 0, i);
        }
        bgCount = 0;

        // set the location of the background
        background.setPosition(GAME_ORIGIN_X, GAME_ORIGIN_Y);

        return background;
    }

    public void run() {
        // the graphics object for this canvas
	Graphics g = getGraphics();

       while(!go){
            g.drawImage(titleImg, getWidth() / 2, getHeight() / 2 - 9, Graphics.HCENTER | Graphics.VCENTER);

            int keyState = getKeyStates();
            if((keyState & GAME_A_PRESSED) !=0){
                go = true;
            }
            
            try {
		  Thread.currentThread().sleep(20);
            } catch(Exception e) {}
        }

        clock =  new Clock(0);
        new Timer().schedule(clock, 0, 100);

	while(!stop) { // infinite loop
            
            time = clock.getTimeElapsed();

            if(time == 0){
                level1 = new Level1(this);
                level1.start();

            }

            moveBackground();

            // first verify game state
            if(time > 1){
                verifyGameState();
            }
            // check user's input
            checkUserInput();

            // update screen
            updateGameScreen(getGraphics());


            // how fast refresh is done
            try {
		  Thread.currentThread().sleep(20);
            } catch(Exception e) {}


        }
        gameOver(g);
        
    }

    private void moveBackground(){
        for (int i = 0; i < 160; i++) {
            background.setCell(i, 0, i+bgCount);
        }
        mLayerManager.append(background);
        bgCount++;
        if(bgCount==500){
            bgCount=0;
        }
    }

    private void verifyGameState() {
        if(lives == 0){
            stop = true;
            return;
        }

        checkForCollision();
        flashPlane();
        checkExp();

    }

    public boolean checkFire(){
        int keyState = getKeyStates();

        if((keyState & GAME_D_PRESSED) !=0){
            bfire = true;
        }
        else{
            bfire=false;
        }
        return bfire;
}

    private void checkUserInput() {
        // get the state of keys
        int keyState = getKeyStates();

        // calculate the position for x axis
        calculatePlaneX(keyState);
        calculatePlaneY(keyState);
}

    private void updateGameScreen(Graphics g) {
        // the next two lines clear the background
        g.setColor(0xffffff);
        g.fillRect(0, 0, getWidth(), getHeight());

        buildGameScreen(g);
        // draws the plane image according to current
        // desired positions
        planeSprite.setRefPixelPosition(planeX, planeY);

        mLayerManager.paint(g, 0, 0);
        checkUpgrade(g);
        titleScreen(g);

        flushGraphics();
    }

    private void calculatePlaneX(int keyState) {
        // determines which way to move and changes the x coordinate accordingly
        if((keyState & LEFT_PRESSED) != 0) {
            planeX = Math.max(GAME_ORIGIN_X + planeImg.getWidth(), planeX - dx);
        }
        else if((keyState & RIGHT_PRESSED) != 0) {
            planeX = Math.min(GAME_ORIGIN_X + GAME_WIDTH, planeX + dx);
        }
    }

    private void calculatePlaneY(int keyState) {
        // determines which way to move and changes the y coordinate accordingly
        if((keyState & UP_PRESSED) != 0) {
            planeY = Math.max(GAME_ORIGIN_Y + planeImg.getHeight()/2, planeY - dy);
        }
        else if((keyState & DOWN_PRESSED) != 0) {
            planeY = Math.min(GAME_ORIGIN_Y + GAME_HEIGHT - planeImg.getHeight()/2, planeY + dy);
        }
    }

    private void buildGameScreen(Graphics g) {
        // set the drawing color to black
        g.setColor(0x000000);

        g.fillRect(0, 0, getWidth(), getHeight());

        background.paint(g);
        //showTimeElapsed(g);
        showScore(g);
        showLives(g);
        showLevel(g);
    }

    private void titleScreen(Graphics g) {
         if(time < 50){
            g.setColor(0x000000);
            g.drawString("Level 1", 60, 80, 0);
            if(time < 16){
                g.drawString("Press '9' to fire", 18, 120, 0);
            }
            if(time >= 20 && time < 25){
                g.setColor(0x000000);
                g.drawString("Start!", 61, 121, 0);
                g.setColor(0xFF0000);
                g.drawString("Start!", 60, 120, 0);
            }
            if(time >= 30 && time < 35){
                g.setColor(0x000000);
                g.drawString("Start!", 61, 121, 0);
                g.setColor(0xFF0000);
                g.drawString("Start!", 60, 120, 0);
            }
            if(time >= 40 && time < 45){
                g.setColor(0x000000);
                g.drawString("Start!", 61, 121, 0);
                g.setColor(0xFF0000);
                g.drawString("Start!", 60, 120, 0);
            }
        }
         if(time >= 580 && time <= 600){
                g.setColor(0x000000);
                g.drawString("Level 2", 61, 121, 0);
                g.setColor(0xFF0000);
                g.drawString("Level 2", 60, 120, 0);
                level = 2;
         }
         if(time >= 1130 && time <= 1150){
                g.setColor(0x000000);
                g.drawString("Level 3", 61, 121, 0);
                g.setColor(0xFF0000);
                g.drawString("Level 3", 60, 120, 0);
                level = 3;
         }
         if(time >= 1690 && time <= 1710){
                g.setColor(0x000000);
                g.drawString("Level 4", 61, 121, 0);
                g.setColor(0xFF0000);
                g.drawString("Level 4", 60, 120, 0);
                level = 4;
         }

    }

    private void showTimeElapsed(Graphics g) {
        g.setColor(0xffffff);
        // what does the clock say
        timeElapsed = clock.getTimeElapsed()/10;

        // draw the time left string
        g.drawString(timeElapsed + " sec", 100, 0, 0);

        // reset the color
        g.setColor(0x000000);
    }

    private void showLevel(Graphics g) {
        // draw the level left string
        g.setColor(0x999999);
        g.drawString("Level "+ level , 101, 16, 0);
        g.setColor(0xffffff);
        g.drawString("Level "+ level , 100, 15, 0);
        // reset the color
        g.setColor(0x000000);
    }

    public LayerManager getManager() {
        return this.mLayerManager;
    }

    private void showScore(Graphics g){      
        //draw score
        g.setColor(0x999999);
        g.drawString("Score: " + score, 6, 1, 0);
        g.setColor(0xffffff);
        g.drawString("Score: " + score, 5, 0, 0);
        g.setColor(0x000000);
    }

    private void showLives(Graphics g){
        //draw lives
        g.setColor(0x999999);
        g.drawString("Lives: " + lives, 6, 16, 0);
        g.setColor(0xffffff);
        g.drawString("Lives: " + lives, 5, 15, 0);
        g.setColor(0x000000);
    }

    private void gameOver(Graphics g){
        g.setColor(0xffffff);
        g.fillRect(0, 0, getWidth(), getHeight());
        
        g.setColor(0x000000);
        g.drawString("Game Over", 46, 91, 0);
        g.drawString("Score: " + score + " pts", 21, 111, 0);
        g.setColor(0xFF0000);
        g.drawString("Game Over", 45, 90, 0);
        g.drawString("Score: " + score + " pts", 20, 110, 0);
        flushGraphics();
    }

     public void checkForCollision() {
        for(int i=0; i<3; i++){
            for(int t=0; t<5; t++){
                enemySprite[i][t] = level1.getEnemySprite(i,t);
                if (planeSprite.collidesWith(enemySprite[i][t], true)) {
                    //make sure the plane isn't in indestructable mode
                    if(indestructable == false){
                        //sets flash to true which resets plane
                        flash = true;
                        flashTime = time * 100;
                        altTime = flashTime;
                        lives--;

                        //adds the explosion sprite
                        planeExpSprite = new Sprite(expImage, 25,25);
                        planeExpSprite.defineReferencePixel(12, 12);

                        planeExpSprite.setPosition(planeX-29, planeY-4);
                        mLayerManager.insert(planeExpSprite, 0);
                        planeExpFrame = 0;

                        //move enemy off screen
                        enemySprite[i][t].setPosition(-10,-10);
                    }
                }
            }
        }
        bonusSprite = level1.getBonusSprite();
        if(planeSprite.collidesWith(bonusSprite, true)){
            mLayerManager.remove(bonusSprite);
            bonusSprite.setPosition(-10, -10);
            weaponUpgrade = 1;
            score = score + 500;
        }
        level1.checkForCollision();
        level1.checkExp();
     }
 
    public void checkExp(){
        //if(time%20 == 0){
            if(planeExpFrame < 36){

               planeExpSprite.nextFrame();
               planeExpFrame ++;

            }
            if(planeExpFrame == 36){
               mLayerManager.remove(planeExpSprite);
            }
        //}
    }

    //flashes plane and set indestructable
    private void flashPlane(){
        if(flash == true){
            if(flashTime - 3500 < altTime) {
                indestructable = true;
                dx = 2;
                dy = 2;
                if(flashTime - 1000 < altTime) {
                    planeSprite.setVisible(false);
                    planeX = CENTER_X;
                    planeY = CENTER_Y;
                    weapon = 0;
                }
                else{
                    if((time % 5) == 0){
                        planeSprite.setVisible(false);
                        weapon = 1;
                    }else{
                        planeSprite.setVisible(true);
                    }
                }
            }else{
                flash = false;
                planeSprite.setVisible(true);
                indestructable = false;              
            }
            flashTime = flashTime + 20;
        }
    }

    public void checkUpgrade(Graphics g){
            if(score >= 10000 && score <= 10200){
                scoreUpgrade[0]++;
            }
            if(score >= 20000 && score <= 20200){
                scoreUpgrade[1]++;
            }
            if(score >= 30000 && score <= 30200){
                scoreUpgrade[2]++;
            }
        for(int u = 0; u < 3; u++){
            if(scoreUpgrade[u] == 1){
                //weapon++;
                //upgradeTime = 0;
                level1.bonus();
                scoreUpgrade[u]++;
            }
        }

        if(weaponUpgrade == 1){
            weapon++;
            upgradeTime = 0;
            weaponUpgrade = 0;
        }
        //Post upgrad message
        if(upgradeTime < 60){
            if(upgradeTime < 20 || upgradeTime > 40){                              
                switch(weapon){
                    case 2: g.setColor(0x000000);
                            g.drawString("Double Missile", 26, 81, 0);
                            g.drawString("Weapon Upgrade", 26, 101, 0);
                            g.setColor(0xFF0000);
                            g.drawString("Double Missile", 25, 80, 0);
                            g.drawString("Weapon Upgrade", 25, 100, 0);
                            break;
                    case 3: g.setColor(0x000000);
                            g.drawString("Supersonic", 41, 81, 0);
                            g.drawString("Speed Upgrade", 31, 101, 0);
                            g.setColor(0xFF0000);
                            g.drawString("Supersonic", 40, 80, 0);
                            g.drawString("Speed Upgrade", 30, 100, 0);
                            break;
                    case 4: g.setColor(0x000000);
                            g.drawString("Triple Missile", 26, 81, 0);
                            g.drawString("Weapon Upgrade", 26, 101, 0);
                            g.setColor(0xFF0000);
                            g.drawString("Triple Missile", 25, 80, 0);
                            g.drawString("Weapon Upgrade", 25, 100, 0);
                            break;
                }
            }
            upgradeTime ++;
            g.setColor(0x000000);
        }
    }

    public int getScore(){
        return this.score;
    }
    
    public Sprite getPlaneExpSprite(){
        return planeExpSprite;
    }

private Image planeImg;
private Sprite planeSprite;
private Image backgroundImg;
private TiledLayer background;
private FighterBulletSprite fighterBulletSprite;
private Level1 level1;
private boolean stop = false;
private int lives = 3;
private Image enemyImage1;
private Sprite bonusSprite;

private LayerManager mLayerManager;

// the plane image coordinates
private int planeX;
private int planeY;

// the distance to move 
public int dx = 2;
public int dy = 2;

// the center of the screen
public final int CENTER_X = getWidth()/2;
public final int CENTER_Y = getHeight()/2;

// the game boundary
public static final int GAME_WIDTH = 160;
public static final int GAME_HEIGHT = 160;

// the shifted x,y origin of the game
public final int GAME_ORIGIN_X = (getWidth() - GAME_WIDTH)/2;
public final int GAME_ORIGIN_Y = (getHeight() - GAME_HEIGHT)/2;

public boolean bfire = false;
public int time;
public Clock clock;
private int timeElapsed;
private Sprite[][] enemySprite = new Sprite[3][5];
private Sprite planeExpSprite;
public int score =0;
public int flashTime = -1;
private boolean flash = false;
private int altTime;
private boolean indestructable;
private int planeExpFrame = 90;
private Image expImage;
public int weapon = 1;
private int weaponUpgrade = 0;
private int[] scoreUpgrade = {0,0,0};
private int upgradeTime = 100;
private int bgCount;
private int level = 1;

private boolean go = false;
private Image titleImg;
}
